//
//  VCDownloadHTTPConnection.m
//  VCDemo
//
//  Created by 肖康龙 on 2017/9/1.
//  Copyright © 2017年 vsoontech. All rights reserved.
//

#import "VCDownloadHTTPConnection.h"
#import "VCDowmload.h"
#import "VCDownloadManger.h"
#import "VCInformationTool.h"

/**m3u8最多返回几个ts*/
#define kM3U8TSNUM 3


@interface VCDownloadHTTPConnection ()

/**是否结束阻塞*/
@property (nonatomic,assign)BOOL isEnd;
/**要加载的路径*/
@property (nonatomic,strong)NSString *fileName;
@end


@implementation VCDownloadHTTPConnection

static NSFileManager *VC_fm;//文件句柄

//扩展HTTPServer支持的请求类型，默认支持GET，HEAD，不支持POST
//请求的
- (BOOL)supportsMethod:(NSString *)method atPath:(NSString *)relativePath
{
    //    VCNSLog(@"我看看你请求了什么%@",relativePath);
    if ([@"POST" isEqualToString:method])
    {
        return YES;
    }
    return [super supportsMethod:method atPath:relativePath];
}

//处量返回的response数据
//返回的
- (NSObject<HTTPResponse> *)httpResponseForMethod:(NSString *)method URI:(NSString *)path
{
    if ([path containsString:@"m3u8"]) {
        [self assemblyM2U8File];
        return [super httpResponseForMethod:method URI:path];
    }
    
    self.fileName = path;
    self.isEnd = NO;//重置为No
    
    VCNSLog(@"看看请求了那些%@ 之后的",path);
    
    if (![VCInformationTool getPlayerIsChangeTime]) [[NSNotificationCenter defaultCenter] postNotificationName:VCDownloadPlayGetTsNotification object:nil userInfo:@{PLAY_NUM_TS:@([self getTsNumWithPath:path])}];//发通知去下载;
    
    [self deleteOverdueTSWithPath:path];
    return [super httpResponseForMethod:method URI:path];
}
/**删除请求过的ts*/
-(void)deleteOverdueTSWithPath:(NSString *)path{
    NSInteger tsNum = [self getTsNumWithPath:path] - 1;
    NSArray *tsFileList = [[VCInformationTool getFileDict] objectForKey:@"fileList"];
    NSInteger listIndex = tsNum - [[[VCInformationTool getFileDict] objectForKey:@"seq"] integerValue];
    if (tsNum >= 0 && listIndex < tsFileList.count) {
//        NSDictionary *tsFile = tsFileList[tsNum];
//        [VCInformationTool deleteFileWithPath:[NSString stringWithFormat:@"%@/%@.%li.ts",kVideoSavePath,tsFile[@"fileId"],(long)tsNum]];
        if ([VCInformationTool freeDiskSpace] < 50*1024*1024) {
            [VCInformationTool deleteFileWithPath:[NSString stringWithFormat:@"%@/%li.ts",kVideoSavePath,(long)tsNum]];
        }
//        [VCInformationTool deleteFileWithPath:[NSString stringWithFormat:@"%@/%li.ts",kVideoSavePath,(long)tsNum]];
    }
    [VCInformationTool setVC_sequence:tsNum+1];
}

/**检查有没有下载完毕*/
-(void)checkDownloadComplete{
    NSArray *array = [[VCInformationTool getTSFileArray] copy];
    for (NSString *fileName in array) {
        if ([fileName containsString:self.fileName]) {
            self.isEnd = YES;
            break;
        }
    }
    
}

/**获取当前ts序号*/
-(NSInteger)getTsNumWithPath:(NSString *)path{
    
    NSString *lastPath = [path lastPathComponent];
    
    NSString *numString = [lastPath substringToIndex:lastPath.length - 3];
    return [numString integerValue];
    
//    NSRange rang = [path localizedStandardRangeOfString:@"."];
//
//    NSString *numTs = [path substringFromIndex:rang.location+1];
//
//    rang = [numTs localizedStandardRangeOfString:@"."];
//    if (rang.location+rang.length < numTs.length) {
//        numTs = [numTs substringToIndex:rang.location];
//
//        return [numTs integerValue];
//    }
//    return 0;
}

/*组装最新的m3u8*/
-(void)assemblyM2U8File{
    
    if ([VCInformationTool getPlayerIsChangeTime]) return;
    
    
    NSInteger getVC_sequence = [VCInformationTool getVC_sequence];
    
    NSInteger dic_seq = [[[VCInformationTool getFileDict] objectForKey:@"seq"] integerValue];
    
    NSString *m3u8 = [NSString stringWithFormat:@"#EXTM3U\n#EXT-X-VERSION:3\n#EXT-X-TARGETDURATION:(MaxTime)\n#EXT-X-MEDIA-SEQUENCE:%ld\n",getVC_sequence];
    
    if (VC_fm == nil) {
        VC_fm = [[NSFileManager alloc] init];
    }
    
    NSArray *tsFileList = [[VCInformationTool getFileDict] objectForKey:@"fileList"];
    NSString *path_movie = kVideoSavePath;
    
    
    
    NSString *path_ts;//ts的路径
    CGFloat duration = 0;
        
    /*在iOS系统中，使用系统播放器播放，如果存在某些TS片，它的EXTINF 取整后，大于EXT-X-TARGETDURATION，但不大于2倍EXT-X-TARGETDURATION，也可以正常播放，例如EXTINF最大值是10.000，EXT-X-TARGETDURATION值为5，可以正常播放，如果EXTINF最大值是10.001，EXT-X-TARGETDURATION值为5，则无法播放。*/
    int targetDuration = 0;//用来记录ts片段最大时间
    
    for (NSInteger i = getVC_sequence ; i < getVC_sequence + kM3U8TSNUM && i < (tsFileList.count + dic_seq); i++) {
        
        NSDictionary *tsFile = tsFileList[i - dic_seq];
//        path_ts = [path_movie stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%li.ts",[tsFile objectForKey:@"fileId"],(long)i]];
        path_ts = [path_movie stringByAppendingPathComponent:[NSString stringWithFormat:@"%li.ts",(long)i]];
        if (![VCInformationTool checkTSFileIsHaveWithTsNum:i]) {//查看本地有没有听说
            
            if ((i == getVC_sequence + 1 && i != 1) || i == getVC_sequence) {//ts没有最新的,那就直接用之前的m3u8文件,不需要重新存储m3u8
                NSLog(@"1111111111不存在的=================");
                [[NSNotificationCenter defaultCenter] postNotificationName:VCDownloadSendDownloadNotification object:nil userInfo:@{PLAY_NUM_TS:@(i)}];//发通知去下载
//                return;
                break;
            }else if(i > getVC_sequence + 1){//ts有新的,需要重新存储m3u8
                NSLog(@"2222222222不存在的=================");
                break;
            }
        }else{
            NSLog(@"存在的=================");
            if (targetDuration < [[tsFile objectForKey:@"duration"] intValue]) {
                targetDuration = [[tsFile objectForKey:@"duration"] intValue];
            }
            duration = [[tsFile objectForKey:@"duration"] floatValue] == 0 ? 10 : [[tsFile objectForKey:@"duration"] floatValue];
//            m3u8 = [NSString stringWithFormat:@"%@#EXTINF:%.3lf,\n%@.%li.ts\n",m3u8,duration,[tsFile objectForKey:@"fileId"],(long)i];
            m3u8 = [NSString stringWithFormat:@"%@#EXTINF:%.3lf,\n%li.ts\n",m3u8,duration,(long)i];
            
        }
    }
    if ([[VCInformationTool getFileDict][@"endList"] boolValue]) {//播到最后了
        m3u8 = [NSString stringWithFormat:@"%@#EXT-X-ENDLIST",m3u8];
        [VCInformationTool setVideoIsLastTs:YES];
    }
    m3u8 = [m3u8 stringByReplacingOccurrencesOfString:@"(MaxTime)" withString:[NSString stringWithFormat:@"%i",targetDuration]];
    
    
    //创建M3U8的链接地址
    NSString *path = [path_movie stringByAppendingPathComponent:@"movie.m3u8"];
    //拼接完成，存储到本地
    NSMutableData *writer = [[NSMutableData alloc] init];
    
    if ([VCInformationTool checkHaveWithPath:kVideoSavePath]) {
        [writer appendData:[m3u8 dataUsingEncoding:NSUTF8StringEncoding]];
        BOOL bSucc = [writer writeToFile:path atomically:YES];
        if (bSucc) {//成功
            VCNSLog(@"M3U8数据保存成功");
        } else {//失败
            VCNSLog(@"M3U8数据保存失败");
        }
    }
    VCNSLog(@"新数据\n%@", m3u8);
}


//处理POST请求提交的数据流(下面方法是改自 Andrew Davidson的类)
- (void)processDataChunk:(NSData *)postDataChunk
{
    VCNSLog(@"processDataChunk function called");
    //multipartData初始化不放在init函数中, 当前类似乎不经init函数初始化
    if (multipartData == nil) {
        multipartData = [[NSMutableArray alloc] init];
    }
    
    //处理multipart/form-data的POST请求中Body数据集中的表单值域并创建文件
    if (!postHeaderOK)
    {
        //0x0A0D: 换行符
        UInt16 separatorBytes = 0x0A0D;
        NSData* separatorData = [NSData dataWithBytes:&separatorBytes length:2];
        
        NSUInteger l = [separatorData length];
        for (int i = 0; i < [postDataChunk length] - l; i++)
        {
            //每次取两个字节 比对下看看是否是换行
            NSRange searchRange = {i, l};
            //如果是换行符则进行如下处理
            if ([[postDataChunk subdataWithRange:searchRange] isEqualToData:separatorData])
            {
                //获取dataStartIndex标识的上一个换行位置到当前换行符之间的数据的Range
                NSRange newDataRange = {dataStartIndex, i - dataStartIndex};
                //dataStartIndex标识的上一个换行位置到移到当前换行符位置
                dataStartIndex = (int)(i + l);
                i += l - 1;
                //获取dataStartIndex标识的上一个换行位置到当前换行符之间的数据
                NSData *newData = [postDataChunk subdataWithRange:newDataRange];
                //如果newData不为空或还没有处理完multipart/form-data中表单变量值域则继续处理剩下的表单值域数据
                if ([newData length] || ![self isBeginOfOctetStream])
                {
                    if ([newData length]) {
                        [multipartData addObject:newData];
                    }
                }
                else
                {
                    //将标识处理完multipart/form-data中表单变量值域的postHeaderOK变量设置为TRUE;
                    postHeaderOK = TRUE;
                    //这里暂时写成硬编码 弊端:每次增加表单变量都要改这里的数值
                    //获取Content-Disposition: form-data; name="xxx"; filename="xxx"
                    NSString* postInfo = [[NSString alloc] initWithBytes:[[multipartData objectAtIndex:4] bytes]
                                                                  length:[[multipartData objectAtIndex:4] length]
                                                                encoding:NSUTF8StringEncoding];
                    VCNSLog(@"postInfo is:%@", postInfo);
                    NSArray* postInfoComponents = [postInfo componentsSeparatedByString:@"; filename="];
                    postInfoComponents = [[postInfoComponents lastObject] componentsSeparatedByString:@"\""];
                    VCNSLog(@"postInfoComponents0 :%@",postInfoComponents);
                    if ([postInfoComponents count]<2)
                    {
                        return;
                    }
                    
                    postInfoComponents = [[postInfoComponents objectAtIndex:1] componentsSeparatedByString:@"\\"];
                    NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
                    NSString* filename = [documentPath stringByAppendingPathComponent:[postInfoComponents lastObject]];
                    VCNSLog(@"filename :%@",filename);
                    NSRange fileDataRange = {dataStartIndex, [postDataChunk length] - dataStartIndex};
                    [[NSFileManager defaultManager] createFileAtPath:filename contents:[postDataChunk subdataWithRange:fileDataRange] attributes:nil];
                    NSFileHandle *file = [NSFileHandle fileHandleForUpdatingAtPath:filename];
                    if (file)
                    {
                        [file seekToEndOfFile];
                        [multipartData addObject:file];
                    }
                    
                    break;
                }
            }
        }
    }
    else //表单值域已经处理过了 这之后的数据全是文件数据流
    {
        [(NSFileHandle*)[multipartData lastObject] writeData:postDataChunk];
    }
    
    float uploadProgress = (double)requestContentLengthReceived / requestContentLength;
    //实际应用时 当前类的实例是相当于单例一样被引用(因为只被实例化一次)
    if (uploadProgress >= 1.0) {
        postHeaderOK = NO;
        multipartData = nil;
    }
    //    [[NSNotificationCenter defaultCenter] postNotificationName:UPLOAD_FILE_PROGRESS object:[NSNumber numberWithFloat:uploadProgress] userInfo:nil];
}
- (void)prepareForBodyWithSize:(UInt64)contentLength
{
    VCNSLog(@"%llu",contentLength);
}

//检查是否已经处理完了multipart/form-data表单中的表单变量
- (BOOL) isBeginOfOctetStream
{
    NSString *octetStreamFlag = @"Content-Type: application/octet-stream";
    NSString *findData = [[NSString alloc] initWithData:(NSData *)[multipartData lastObject] encoding:NSUTF8StringEncoding];
    
    for (NSData *d in multipartData) {
        NSString *temp = [[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding] ;
        VCNSLog(@"multipartData items: %@", temp);
    }
    //如果已经处理完了multipart/form-data表单中的表单变量
    if ( findData != nil && [findData length] > 0 )
    {
        VCNSLog(@"findData is :%@\n octetStreamFlag is :%@", findData, octetStreamFlag);
        if ([octetStreamFlag isEqualToString:findData]) {
            VCNSLog(@"multipart/form-data 变量值域数据处理完毕");
            return YES;
        }
        return NO;
    }
    return NO;
    
}


@end
